#include "finite_state_machine.h"
BEG_DEF_NAMESPACE_FSM
FSMState::FSMState(){
	mStateCode = BEFORE_BEGIN;
	Action = NULL;
}
int FSMState::BuildState( FSM_STATE_CODE  stateCode , FSM_ACTION action , ... ){
	mStateCode = stateCode;
	Action 	   = action;

	va_list args;
	va_start(args, action);
	while (1){
		FSM_STATE_CODE sCode = va_arg( args, FSM_STATE_CODE );
		if( sCode <= BEFORE_BEGIN ){
			break;
		}
		mSubStateCodeSet.insert( sCode );
	}
	va_end(args);
	return 0;
}
bool FSMState::IsSubStateCode( FSM_STATE_CODE stateCode ){
	return (mSubStateCodeSet.find(stateCode) != mSubStateCodeSet.end());
}

FSM::FSM(){
	mCurrStateCode	= BEFORE_BEGIN;
	mBeginStateCode	= BEFORE_BEGIN;
	mEndStateCode	= AFTER_END;
}

FSMState * FSM::FindState( FSM_STATE_CODE stateCode ){
	FSM_STATE_MAP::iterator iter = mStateMap.find( stateCode );
	if( iter == mStateMap.end() ){
		return NULL;
	}
	return iter->second;
}
int FSM::CheckState( FSM_STATE_CODE stateCode , FSMState ** ppState ){
	/* check if the state code is valid*/
	if( !ISVALIDSTATE( stateCode ) ){
		return ERR_STATE_INVALID;
	}

	/* check if the stateCode is exist */
	FSMState * ptmpState = NULL;
	if( ( ptmpState = FindState(stateCode)) == NULL  ){
		return ERR_STATE_NOTEXIST; 
	}
	if( ppState ){
		*ppState = ptmpState;
	}
	return OK;
}


int FSM::BuildFSM( FSM_STATE_CODE beginStateCode , 
		   FSM_STATE_CODE endStateCode , ... ){


	va_list args;
	int retVal = OK ;

	FSM_STATE_CODE tmpStateCode;
	FSMState * ptmpState;

	va_start(args, endStateCode);
	while (1){
		ptmpState = va_arg( args, FSMState* );
		if( ptmpState == NULL ||
		    (tmpStateCode = ptmpState->mStateCode) == endStateCode ){
			break;
		}

		/* there must be unique object per state code in the state code map */
		if( (retVal = CheckState( tmpStateCode, NULL)) != ERR_STATE_NOTEXIST ){
			return  retVal == OK?ERR_STATE_DUPLICATE:retVal;
		}

		mStateMap.insert( std::make_pair(tmpStateCode , ptmpState) );
	}
	va_end(args);

	/* check the start state */
	if( (retVal=CheckState( beginStateCode , NULL)) != OK ){
		return retVal;
	}
	mBeginStateCode = beginStateCode;
	mCurrStateCode = beginStateCode;

	/* check the end state */
	if( (retVal = CheckState( endStateCode , NULL)) != OK ){
		return retVal;
	}
	mEndStateCode = endStateCode ;

	return OK;
}

int FSM::Trigger( void * pData ){
	int retVal;
	FSM_STATE_CODE tmpStateCode = BEFORE_BEGIN;
	FSMState * ptmpState;

	if( (retVal = CheckState( mCurrStateCode , &ptmpState )) != OK ){
		return retVal;
	}

	/*check if the returned state code is the sub state of current state */
	tmpStateCode = ptmpState->Action( ptmpState , pData );
	if( ptmpState->IsSubStateCode(tmpStateCode) ){
		mCurrStateCode = tmpStateCode ;
	}else{
		return ERR_NOT_SUB_STATE;
	}
}

END_DEF_NAMESPACE_FSM

